package org.hentor.modules.generate.generate.fileGenrate;

import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.hentor.common.exception.HentorAdminException;
import org.hentor.modules.generate.dto.GenerateFileDTO;
import org.hentor.modules.generate.generate.enums.GenerateJavaType;
import org.hentor.modules.generate.utils.CamelCaseUtil;
import org.hentor.generate.entity.GenerateDevDetail;
import org.hentor.generate.entity.GenerateDevMain;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.*;

/**
 * 后端代码生成
 */
@Slf4j
public class JavaFileGenerate extends AbstractFileGenerate{

    @Override
    public List<String> generate(GenerateFileDTO generateFileDTO) {
        //固定路径
        String tempPath = "hentor-generate.hentor-generate-service.src.main.resources.temp.java.";
        ArrayList<String> pathList = new ArrayList<>();
        //实体生成
        pathList.add(generateEntity(generateFileDTO,tempPath));
        //DTO生成
        pathList.add(generateDto(generateFileDTO,tempPath));
        //mapper生成
        pathList.add(generateMapper(generateFileDTO,tempPath));
        //mapperXml生成
        pathList.add(generateMapperXml(generateFileDTO,tempPath));
        //service生成
        pathList.add(generateService(generateFileDTO,tempPath));
        //serviceImpl生成
        pathList.add(generateServiceImpl(generateFileDTO,tempPath));
        //controller生成
        pathList.add(generateController(generateFileDTO,tempPath));
        return pathList;
    }
    /**
     * Controller层生成
     * @return
     */
    private String generateController(GenerateFileDTO generateFileDTO,String tempPath){
        GenerateDevMain generateDevMain = generateFileDTO.getGenerateDevMain();
        VelocityEngine velocityEngine = generateFileDTO.getVelocityEngin();
        String entityFileName = CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(), true);
        //自定义包名
        String packagePath = generateFileDTO.getPackagePath();
        //entity包名
        String entityPackagePath =".controller";
        //全路径
        String path = (tempPath+packagePath+entityPackagePath).replace(".", "/");;
        //entity文件名
        Template template = velocityEngine.getTemplate("templates/java/Controller.vm");
        VelocityContext context = new VelocityContext();
        context.put("packagePath", packagePath+entityPackagePath);
        context.put("entityName", entityFileName);
        context.put("tableDesc", generateDevMain.getTableDescription());
        context.put("entityNameLower", CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(), false));
        context.put("dtoNameLower", CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(), false) + "DTO");
        context.put("dtoName", CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(), true) + "DTO");
        ArrayList<String> imports = new ArrayList<>();
        imports.add(packagePath + ".entity." +entityFileName);
        imports.add(packagePath + ".dto." +entityFileName+"DTO");
        imports.add(packagePath+".service.I"+entityFileName+"Service");
        context.put("imports", imports);
        ArrayList<String> fields = new ArrayList<>();
        generateFileDTO.getGenerateDevDetailList().forEach(x->{
            if(x.getIsQuery() != null && x.getIsQuery() == 1){
                fields.add(CamelCaseUtil.underscoreToCamelCase(x.getColumnName(),true));
            }
        });
        context.put("fields", fields);
        File  directory = new File(path);
        if (!directory.exists()) {
            boolean mkdirs = directory.mkdirs();
            if(!mkdirs){
                throw new HentorAdminException(path+"目录创建失败！");
            }
        }
        String filePath = path+"/"+entityFileName+"Controller"+".java";
        try (Writer writer = new FileWriter(filePath)) {
            template.merge(context, writer);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(String.format("controller文件生成成功，路径%s",filePath));
        return filePath;
    }

    /**
     * serviceImpl层生成
     * @return
     */
    private String generateServiceImpl(GenerateFileDTO generateFileDTO,String tempPath){
        GenerateDevMain generateDevMain = generateFileDTO.getGenerateDevMain();
        VelocityEngine velocityEngine = generateFileDTO.getVelocityEngin();
        String entityFileName = CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(), true);
        //自定义包名
        String packagePath = generateFileDTO.getPackagePath();
        //entity包名
        String entityPackagePath =".service";
        //全路径
        String path = (tempPath+packagePath+entityPackagePath+".impl").replace(".", "/");;
        //entity文件名
        Template template = velocityEngine.getTemplate("templates/java/ServiceImpl.vm");
        VelocityContext context = new VelocityContext();
        context.put("packagePath", packagePath+entityPackagePath);
        context.put("entityName", entityFileName);
        ArrayList<String> imports = new ArrayList<>();
        imports.add(packagePath + ".entity." +entityFileName);
        imports.add(packagePath+".mapper."+entityFileName+"Mapper");
        imports.add(packagePath+".service.I"+entityFileName+"Service");
        context.put("imports", imports);
        File  directory = new File(path);
        if (!directory.exists()) {
            boolean mkdirs = directory.mkdirs();
            if(!mkdirs){
                throw new HentorAdminException(path+"目录创建失败！");
            }
        }
        String filePath = path+"/"+entityFileName+"ServiceImpl"+".java";
        try (Writer writer = new FileWriter(filePath)) {
            template.merge(context, writer);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(String.format("serviceImpl文件生成成功，路径%s",filePath));
        return filePath;
    }


    /**
     * service层生成
     * @return
     */
    private String generateService(GenerateFileDTO generateFileDTO,String tempPath){
        GenerateDevMain generateDevMain = generateFileDTO.getGenerateDevMain();
        VelocityEngine velocityEngine = generateFileDTO.getVelocityEngin();
        String entityFileName = CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(), true);
        //自定义包名
        String packagePath = generateFileDTO.getPackagePath();
        //entity包名
        String entityPackagePath =".service";
        //全路径
        String path = (tempPath+packagePath+entityPackagePath).replace(".", "/");;
        //entity文件名
        Template template = velocityEngine.getTemplate("templates/java/Service.vm");
        VelocityContext context = new VelocityContext();
        context.put("packagePath", packagePath+entityPackagePath);
        context.put("entityName", entityFileName);
        context.put("imports", Collections.singletonList(packagePath + ".entity." +entityFileName));
        File  directory = new File(path);
        if (!directory.exists()) {
            boolean mkdirs = directory.mkdirs();
            if(!mkdirs){
                throw new HentorAdminException(path+"目录创建失败！");
            }
        }
        String filePath = path+"/I"+entityFileName+"Service"+".java";
        try (Writer writer = new FileWriter(filePath)) {
            template.merge(context, writer);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(String.format("service文件生成成功，路径%s",filePath));
        return filePath;
    }

    /**
     * mapper层生成
     * @return
     */
    private String generateMapper(GenerateFileDTO generateFileDTO,String tempPath){
        GenerateDevMain generateDevMain = generateFileDTO.getGenerateDevMain();
        VelocityEngine velocityEngine = generateFileDTO.getVelocityEngin();
        String entityFileName = CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(), true);
        //自定义包名
        String packagePath = generateFileDTO.getPackagePath();
        //entity包名
        String entityPackagePath =".mapper";
        //全路径
        String path = (tempPath+packagePath+entityPackagePath).replace(".", "/");;
        //entity文件名
        Template template = velocityEngine.getTemplate("templates/java/Mapper.vm");
        VelocityContext context = new VelocityContext();
        context.put("packagePath", packagePath+entityPackagePath);
        context.put("entityName", entityFileName);
        context.put("imports", Collections.singletonList(packagePath + ".entity." +entityFileName));
        File  directory = new File(path);
        if (!directory.exists()) {
            boolean mkdirs = directory.mkdirs();
            if(!mkdirs){
                throw new HentorAdminException(path+"目录创建失败！");
            }
        }
        String filePath = path+"/"+entityFileName+"Mapper"+".java";
        try (Writer writer = new FileWriter(filePath)) {
            template.merge(context, writer);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(String.format("mapper文件生成成功，路径%s",filePath));
        return filePath;
    }

    /**
     * mapperXml生成
     * @return
     */
    private String generateMapperXml(GenerateFileDTO generateFileDTO,String tempPath){
        GenerateDevMain generateDevMain = generateFileDTO.getGenerateDevMain();
        VelocityEngine velocityEngine = generateFileDTO.getVelocityEngin();
        String entityFileName = CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(), true);
        //自定义包名
        String packagePath = generateFileDTO.getPackagePath();
        //entity包名
        String entityPackagePath =".mapper";
        //全路径
        String path = (tempPath+packagePath+entityPackagePath+".xml").replace(".", "/");;
        //entity文件名
        Template template = velocityEngine.getTemplate("templates/java/MapperXml.vm");
        VelocityContext context = new VelocityContext();
        context.put("mapperPath", packagePath+entityPackagePath+"."+entityFileName+"Mapper");
        File  directory = new File(path);
        if (!directory.exists()) {
            boolean mkdirs = directory.mkdirs();
            if(!mkdirs){
                throw new HentorAdminException(path+"目录创建失败！");
            }
        }
        String filePath = path+"/"+entityFileName+"Mapper"+".xml";
        try (Writer writer = new FileWriter(filePath)) {
            template.merge(context, writer);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(String.format("mapperXml文件生成成功，路径%s",filePath));
        return filePath;
    }

    /**
     * DTO生成
     * @return
     */
    private String generateDto(GenerateFileDTO generateFileDTO,String tempPath){
        GenerateDevMain generateDevMain = generateFileDTO.getGenerateDevMain();
        List<GenerateDevDetail> generateDevDetailList = generateFileDTO.getGenerateDevDetailList();
        VelocityEngine velocityEngine = generateFileDTO.getVelocityEngin();

        //自定义包名
        String packagePath = generateFileDTO.getPackagePath();
        //entity包名
        String entityPackagePath =".dto";
        //全路径
        String path = (tempPath+packagePath+entityPackagePath).replace(".", "/");;
        //dto文件
        Template template = velocityEngine.getTemplate("templates/java/Dto.vm");
        VelocityContext context = new VelocityContext();
        context.put("packagePath", packagePath+entityPackagePath);
        context.put("entityName", CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(),true));
        ArrayList<String> typeList = new ArrayList<>();
        List<HashMap<String, String>> fields = new ArrayList<>();
        //只生成需要查询的字段
        generateDevDetailList.stream().filter(x->x.getIsQuery() != null && x.getIsQuery() == 1).forEach(x->{
            fields.add(createField(GenerateJavaType.getDescByCode(x.getColumnType()), CamelCaseUtil.underscoreToCamelCase(x.getColumnName(),false), x.getColumnDesc()));
            typeList.add(GenerateJavaType.getDescByCode(x.getColumnType()));
        });
        context.put("imports", generateImports(typeList));
        context.put("fields", fields);
        File  directory = new File(path);
        if (!directory.exists()) {
            boolean mkdirs = directory.mkdirs();
            if(!mkdirs){
                throw new HentorAdminException(path+"目录创建失败！");
            }
        }
        String filePath = path+"/"+CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(),true)+"DTO.java";
        try (Writer writer = new FileWriter(filePath)) {
            template.merge(context, writer);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(String.format("dto文件生成成功，路径%s",filePath));
        return filePath;
    }



    /**
     * entity实体生成
     * @return
     */
    private String generateEntity(GenerateFileDTO generateFileDTO,String tempPath){
        GenerateDevMain generateDevMain = generateFileDTO.getGenerateDevMain();
        List<GenerateDevDetail> generateDevDetailList = generateFileDTO.getGenerateDevDetailList();
        VelocityEngine velocityEngine = generateFileDTO.getVelocityEngin();

        //自定义包名
        String packagePath = generateFileDTO.getPackagePath();
        //entity包名
        String entityPackagePath =".entity";
        //全路径
        String path = (tempPath+packagePath+entityPackagePath).replace(".", "/");;
        //entity文件名
        Template template = velocityEngine.getTemplate("templates/java/Entity.vm");
        VelocityContext context = new VelocityContext();
        context.put("packagePath", packagePath+entityPackagePath);
        context.put("entityName", CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(),true));
        context.put("tableName", generateDevMain.getTableName());
        ArrayList<String> typeList = new ArrayList<>();
        List<HashMap<String, String>> fields = new ArrayList<>();
        generateDevDetailList.forEach(x->{
            fields.add(createField(GenerateJavaType.getDescByCode(x.getColumnType()), CamelCaseUtil.underscoreToCamelCase(x.getColumnName(),false), x.getColumnDesc()));
            typeList.add(GenerateJavaType.getDescByCode(x.getColumnType()));
        });
        context.put("imports", generateImports(typeList));
        context.put("fields", fields);
        File  directory = new File(path);
        if (!directory.exists()) {
            boolean mkdirs = directory.mkdirs();
            if(!mkdirs){
                throw new HentorAdminException(path+"目录创建失败！");
            }
        }
        String filePath = path+"/"+CamelCaseUtil.underscoreToCamelCase(generateDevMain.getTableName(),true)+".java";
        try (Writer writer = new FileWriter(filePath)) {
            template.merge(context, writer);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info(String.format("entity文件生成成功，路径%s",filePath));
        return filePath;
    }


    private static List<String> generateImports(List<String> types) {
        List<String> imports = new ArrayList<>();
        for (String type : types) {
            if ("Date".equals(type)) {
                imports.add("java.util.Date");
            }else if("BigDecimal".equals(type)){
                imports.add("import java.math.BigDecimal");
            }
        }
        return imports;
    }

    private static HashMap<String, String> createField(String type, String name, String description) {
        HashMap<String, String> field = new HashMap<>(3);
        field.put("type", type);
        field.put("name", name);
        field.put("description", description);
        return field;
    }
}
